#pragma once

#include <exception>
#include "kconfig.h"

#ifdef _FULLPROGRAM

enum KLexicalErrorEnum
{
	KLE_EXPECT_QUOTE,
	KLE_INVALID_CHAR
};

static const char *lexErr[] =
{
	"Expect double-quote.",
	"Invalid character."
};

class KLexicalError : std::exception
{
public:
	const char *errMsg;
	k_uint line;

	KLexicalError(KLexicalErrorEnum err, k_uint ln = 0)
	{
		this->errMsg = ::lexErr[err];
		this->line = ln;
	};
};

enum KSyntaxErrorEnum
{
	KSE_EXPECT_EOS,
	KSE_EXPECT_VAR,
	KSE_EXPECT_TYPE,
	KSE_EXPECT_VAR_TYPE,
	KSE_EXPECT_LITINT,
	KSE_EXPECT_LABEL,
	KSE_EXPECT_COLON,
	KSE_EXPECT_EQU,
	KSE_EXPECT_EXPR,
	KSE_EXPECT_OPERATOR,
	KSE_EXPECT_LPAR,
	KSE_EXPECT_RPAR,
	KSE_INCONSISTENT_ARG_COUNT,
	KSE_EXPECT_OBJECT,
	KSE_EXPECT_SELECTOR,
	KSE_EXPECT_IO_METHOD,
	KSE_EXPECT_VAR_METHOD,
	KSE_EXPECT_STACK_METHOD,
	KSE_EXPECT_TAPE_METHOD,
	KSE_EXPECT_CTRL_METHOD
};

static const char *synErr[] =
{
	"Expect end of statement.",
	"Expect variable.",
	"Expect type.",
	"Expect variable or type.",
	"Expect integer literal.",
	"Expect label.",
	"Expect colon.",
	"Expect '='.",
	"Expect expression.",
	"Expect operator.",
	"Expect left parenthesis.",
	"Expect right parenthesis.",
	"Inconsistent argument count.",
	"Expect object.",
	"Expect selector.",
	"Expect io method.",
	"Expect var method.",
	"Expect stack method.",
	"Expect tape method.",
	"Expect ctrl method.",
};

class KSyntaxError : std::exception
{
public:
	const char *errMsg;
	k_uint line;

	KSyntaxError(KSyntaxErrorEnum err, k_uint ln = 0)
	{
		this->errMsg = ::synErr[err];
		this->line = ln;
	}
};

enum KCompileErrorEnum
{
	KCE_DUPLICATED_VAR,
	KCE_UNDECLARED_VAR,
	KCE_DUPLICATED_LABEL,
	KCE_UNDECLARED_LABEL,
	KCE_TYPE_MISMATCHED
};

static const char *cmpErr[] =
{
	"Duplicated variable.",
	"Undeclared variable.",
	"Duplicated label.",
	"Undeclared label.",
	"Type mismatched."
};

class KCompileError : std::exception
{
public:
	const char *errMsg;
	k_uint line;

	KCompileError(KCompileErrorEnum err, k_uint ln = 0)
	{
		this->errMsg = ::cmpErr[err];
		this->line = ln;
	}
};

#endif //_FULLPROGRAM

enum KRuntimeErrorEnum
{
	KRE_ILLEGAL_OPCODE,
	KRE_CANT_CVI,
	KRE_CANT_CVR,
	KRE_STACK_EMPTY,
	KRE_TAPE_INDEX_OOR,
	KRE_CODE_OFFSET_OOR,
	KRE_TYPE_MISMATCHED,
	KRE_STACK_PTR_OOR
};

static const char *runErr[] =
{
	"Illegal opcode.",
	"Can not convert object to int.",
	"Can not convert object to real.",
	"Stack empty.",
	"Tape index out of range.",
	"Code offset out of range.",
	"Type mismatched.",
	"Stack pointer out of range."
};

class KRuntimeError : std::exception
{
public:
	const char *errMsg;
	k_uint line;

	KRuntimeError(KRuntimeErrorEnum err, k_uint ln = 0)
	{
		this->errMsg = ::runErr[err];
		this->line = ln;
	}
};
